/*
 * FunctionAnalyzer_test.cpp
 *
 *  Created on: 7 июн. 2022 г.
 *      Author: nikitas
 */
#include "FunctionAnalyzer_test.h"

namespace STC_calc
{

const std::vector<std::function<std::pair<bool, std::string>(void)>> FunctionAnalyzer_test::test_vector
{
	&is_open_bracket, &remove_brackets, &has_base, &base_define, &find_without_brackets, &simplify_string,
	&define_name_function, &define_func_args, &is_it_close_bracket, &define_open_bracket_type
};

bool FunctionAnalyzer_test::is_vectors_equal(const string_vector& vec1, const string_vector& vec2)
{
	if (vec1.size() != vec2.size()) return false;
	int i = 0;
	for (auto v : vec1)
	{
		if (v != vec2[i]) return false;
		i++;
	}
	return true;
}
std::string FunctionAnalyzer_test::vector_to_str(const string_vector& args)
{
	std::string ret = "";
	for (auto str : args)
	{
		ret+=str;
		ret+=", ";
	}
	return ret;
}

bool FunctionAnalyzer_test::test_all()
{
	std::pair<bool, std::string> ret;
	for (auto func : test_vector)
	{
		ret = func();
		Logger::put(ret.second);
		if (!ret.first) return false;
	}
	return true;
}

std::pair<bool, std::string> FunctionAnalyzer_test::is_open_bracket()
{
	const std::string alf = "abcdefghijklmnopqrstuvwxyz1234567890]})";
	const std::string log = "[ERROR] FunctionAnalyzer::is_open_bracket() doesn't work";

	std::pair<bool, std::string> OK(true, "[OK] FunctionAnalyzer::is_open_bracket() works correctly");
	std::pair<bool, std::string> ERROR(false, log);

	for (auto l : alf)
	{
		std::string letter = std::to_string(l);
		if (FunctionAnalyzer::is_open_bracket(letter)) return ERROR;
	}

	if (!FunctionAnalyzer::is_open_bracket("(")) return ERROR;
	if (!FunctionAnalyzer::is_open_bracket("{")) return ERROR;
	if (!FunctionAnalyzer::is_open_bracket("[")) return ERROR;

	return OK;
}
std::pair<bool, std::string> FunctionAnalyzer_test::remove_brackets()
{
	std::string correct = "J3w)S";
	string_vector args = {"(J3w)S)", "((J3w)S))", "(((J3w)S)))"};

	std::string log = "[ERROR] FunctionAnalyzer::remove_brackets() doesn't work: ";
	std::pair<bool, std::string> OK(true, "[OK] FunctionAnalyzer::remove_brackets() works correctly");

	for (auto str :args)
	{
		FunctionAnalyzer::remove_brackets(str);
		if (str != correct)
		{
			log+= str + "get " + correct + "should be";
			std::pair<bool, std::string> ERROR(false, log);
			return ERROR;
		}
	}
	return OK;
}

std::pair<bool, std::string> FunctionAnalyzer_test::simplify_string()
{
	const std::vector<std::pair<std::string, std::string>> args =
	{
		{"a+b", "+"}, {"a-b", "-"}, {"va*2b", "*"}, {"aea/23b", "/"}, {"3a+b2+c122", "++"},
		{"a+b-c", "+-"}, {"(a+b)+c", "+"}, {"(a+b)-c", "-"}, {"[+++EMPEROR+++]+a", "+"}, {"[meh]-a", "-"},
		{"{1000 - 3}*ad", "*"}, {"sum 1 2 3 4 5", "sum"}, {"log(45;31251243)", "log"}, {"sin(45)", "sin"},
		{"a*x^2", "*^"}, {"a*x^2 + b*x + c", "*^+*+"}, {"(sin(a+b)-c", "-"}
	};
	for (auto pair : args)
	{
		auto ret = FunctionAnalyzer::simplify_string(pair.first);
		if (pair.second != ret)
		{
			std::string log = "[ERROR] FunctionAnalyzer::simplify_string() doesn't works correctly";
			log +="\n" + pair.first + " get; should be " + pair.second + "; but returned " + ret;
			std::pair<bool, std::string> ERROR(false, log);
			return ERROR;
		}
	}
	std::pair<bool, std::string> OK(true, "[OK] FunctionAnalyzer::simplify sting() works correctly");
	return OK;
}

std::pair<bool, std::string> FunctionAnalyzer_test::has_base()
{
	const string_vector a = {"abs", "cringe", "sum", "div"};
	std::string correct = "log";

	std::pair<bool, std::string> OK(true, "[OK] FunctionAnalyzer::has_base() works correctly");
	std::string log = "[ERROR] FunctionAnalyzer::has_base() doesn't work";

	for (auto s : a)
	{
		if (FunctionAnalyzer::has_base(s))
		{
			log +="\n" + s + " get; should be false";
			std::pair<bool, std::string> ERROR(false, log);
			return ERROR;
		}
	}

	if (!FunctionAnalyzer::has_base(correct))
	{
		log +="\n" + correct + " get; should be true";
		std::pair<bool, std::string> ERROR(false, log);
		return ERROR;
	}

	return OK;
}

std::pair<bool, std::string> FunctionAnalyzer_test::base_define()
{
	const string_vector a = {"abs", "cringe", "sum", "div"};
	std::string correct = "log";

	std::pair<bool, std::string> OK(true, "[OK] FunctionAnalyzer::base_define() works correctly");

	std::string log = "[ERROR] FunctionAnalyzer::base_define() doesn't work ";

	std::string str = "log(32;12231)";

	std::string ret = FunctionAnalyzer::base_define(str, "log");
	if (ret != "32")
	{
		log+= "should be 32, but get " + ret;
		std::pair<bool, std::string> ERROR(false, log);
		return ERROR;
	}
	if (str != "12231")
	{
		log+= "should be 12231, but get " + str;
		std::pair<bool, std::string> ERROR(false, log);
		return ERROR;
	}

	return OK;
}

std::pair<bool, std::string> FunctionAnalyzer_test::find_without_brackets()
{
	const std::vector<std::pair<std::string, int>> args =
	{
		{"012345+7890", 6}, {"(+)345678+", 9}, {"{+}345+", 6}, {"[+]3456+", 7},
	};
	for (auto pair : args)
	{
		auto ret = FunctionAnalyzer::find_without_brackets(pair.first, "+");
		if (pair.second != ret)
		{
			std::string log = "[ERROR] FunctionAnalyzer::find_without_brackets() doesn't works correctly";
			log +="\n" + pair.first + " get; should be " + std::to_string(pair.second) + "; but returned " + std::to_string(ret);
			std::pair<bool, std::string> ERROR(false, log);
			return ERROR;
		}
	}
	std::pair<bool, std::string> OK(true, "[OK] FunctionAnalyzer::find_without_brackets() works correctly");
	return OK;
}

std::pair<bool, std::string> FunctionAnalyzer_test::is_it_close_bracket()
{
	const std::vector<std::pair<std::string, Enums::brackets_types>> false_args =
	{
		{"[", Enums::brackets_types::standart}, {"d", Enums::figure}, {")", Enums::square}, {"}", Enums::not_a_bracket},
	};
	const std::vector<std::pair<std::string, Enums::brackets_types>> true_args =
	{
		{")", Enums::standart}, {"}", Enums::figure}, {"]", Enums::square}
	};
	for (auto pair : false_args)
	{
		if (FunctionAnalyzer::is_it_close_bracket(pair.first, pair.second))
		{
			std::string log = "[ERROR] FunctionAnalyzer::is_it_close_bracket() doesn't works correctly";
			std::pair<bool, std::string> ERROR(false, log);
			return ERROR;
		}
	}
	for (auto pair : true_args)
	{
		if (!FunctionAnalyzer::is_it_close_bracket(pair.first, pair.second))
		{
			std::string log = "[ERROR] FunctionAnalyzer::is_it_close_bracket() doesn't works correctly";
			std::pair<bool, std::string> ERROR(false, log);
			return ERROR;
		}
	}
	std::pair<bool, std::string> OK(true, "[OK] FunctionAnalyzer::is_it_close_bracket() works correctly");
	return OK;
}
std::pair<bool, std::string> FunctionAnalyzer_test::define_open_bracket_type()
{
	const std::vector<std::pair<std::string, Enums::brackets_types>> args =
	{
		{"(", Enums::brackets_types::standart}, {"{", Enums::figure}, {"[", Enums::square}, {"C", Enums::not_a_bracket},
	};
	for (auto pair : args)
	{
		auto ret = FunctionAnalyzer::define_open_bracket_type(pair.first);
		if (pair.second != ret)
		{
			std::string log = "[ERROR] FunctionAnalyzer::define_open_bracket_type() doesn't works correctly";
			std::pair<bool, std::string> ERROR(false, log);
			return ERROR;
		}
	}
	std::pair<bool, std::string> OK(true, "[OK] FunctionAnalyzer::define_open_bracket_type() works correctly");
	return OK;
}

std::pair<bool, std::string> FunctionAnalyzer_test::define_name_function()
{
	const std::vector<std::pair<std::string, std::string>> args =
	{
		{"a+b", "sum"}, {"a*b","mult"}, {"a-b","diff"}, {"a/b", "div"}, {"a^b", "pow"}, {"log(c;a+b)","log"},
		{"ln(42)", "ln"}, {"lg(532)", "lg"}, {"sin(30)", "sin"}, {"[+++U+++]*2", "mult"}, {"(a+b)*c", "mult"},
		{"{2+2+2+2+2}*100", "mult"}, {"sin(30)*2", "mult"}
	};
	for (auto pair : args)
	{
		auto ret = FunctionAnalyzer::define_name_function(pair.first);
		if (pair.second != ret)
		{
			std::string log = "[ERROR] FunctionAnalyzer::define_name_function() doesn't works correctly";
			log +="\n" + pair.first + " get; should be " + pair.second + "; but returned " + ret;
			std::pair<bool, std::string> ERROR(false, log);
			return ERROR;
		}
	}
	std::pair<bool, std::string> OK(true, "[OK] FunctionAnalyzer::define_name_function() works correctly");
	return OK;
}
std::pair<bool, std::string> FunctionAnalyzer_test::define_func_args()
{
	const std::vector<std::pair<std::pair<std::string, std::string>, string_vector>> args =
	{
		{{"a+b","sum"}, {"a","b"}}, {{"2+2","sum"}, {"2","2"}}, {{"a*b", "mult"},{"a","b"}}, {{"a/b", "div"},{"a","b"}},
		{{"a^b","pow"},{"a","b"}}, {{"log(a;b)","log"},{"a","b"}},
		{{"sin(a)","sin"},{"(a)"}}, {{"ln(a)","ln"},{"(a)"}},
		{{"a+b*c","sum"},{"a","b*c"}}, {{"(a+b)+c","sum"},{"(a+b)","c"}},
		{{"[+++]+c","sum"},{"[+++]","c"}}, {{"{2+2+2*3}+a","sum"},{"{2+2+2*3}","a"}}
	};
	for (auto pair : args)
	{
		string_vector ret = FunctionAnalyzer::define_func_args(pair.first.first, pair.first.second);
		if (!is_vectors_equal(ret, pair.second))
		{
			std::string log = "[ERROR] FunctionAnalyzer::define_func_args() doesn't works correctly";
			log +="\n" + pair.first.first +":" + pair.first.second;
			log += " get; should be {" + vector_to_str(pair.second);
			log += "}; but returned {" + vector_to_str(ret) + "}";
			std::pair<bool, std::string> ERROR(false, log);
			return ERROR;
		}
	}
	std::pair<bool, std::string> OK(true, "[OK] FunctionAnalyzer::define_func_args() works correctly");
	return OK;
}
}


